﻿using System;
using System.IO;
using System.Text;

namespace CommLib
{
    public enum BtMessageType {
		Status, Battery, Request, Signal, SMS, Contacts, SmsList, ThreadList, Conversation, Calendar, CalendarList, CallLog
	}

    public abstract class BluetoothMessage
    {
        protected static readonly char FIELD_DELIMITER = '\f';
	    public readonly BtMessageType ID;
	    protected string[] mData;
        private readonly static DateTime DATE_TIME_OFFSET = new DateTime(1970, 1, 1, 0, 0, 0, 0);

        protected BluetoothMessage(BtMessageType id, string[] data) {
		    ID = id;
		    mData = data;
	    }

	    protected BluetoothMessage(BtMessageType id, byte[] data, int length) {
		    ID = id;

		    // Offset = 5, wegen 1 Byte ID und 4 Byte Länge
		    // Länge = length - 1, weil 1 Byte ID (4 Byte Länge nicht in length
		    // enthalten)
            UTF8Encoding enc = new UTF8Encoding();
            mData = enc.GetString(data, 5, length - 1).Split(FIELD_DELIMITER);
	    }

        public override string ToString()
        {
            if (mData != null)
            {
                StringBuilder retval = new StringBuilder();

                for (int i = 0; i < mData.Length; i++)
                {
                    retval.Append(mData[i]);

                    if (i < mData.Length - 1)
                        retval.Append(FIELD_DELIMITER);
                }

                return retval.ToString();
            }
            else
                return "";
        }

        public byte[] getBytes()
        {
            string tmp = (char)((int)ID) + ToString();
            char[] chars = tmp.ToCharArray();

            MemoryStream ms = new MemoryStream(4 + chars.Length);
            BinaryWriter br = new BinaryWriter(ms, Encoding.UTF8);

            // .Net arbeitet mit LittleEndian, Java mit BigEndian
            br.Write(switchEndianness(chars.Length));
            br.Write(chars);

            return ms.GetBuffer();
        }

        public static int switchEndianness(int number)
        {
            // Get the raw bytes  
            byte[] byteArray = BitConverter.GetBytes(number);

            // Store the raw bytes into individual bytes.  
            byte b0 = byteArray[0];
            byte b1 = byteArray[1];
            byte b2 = byteArray[2];
            byte b3 = byteArray[3];

            // Swap the order of the bytes in the byteArray to switch endianness.  
            byteArray[0] = b3;
            byteArray[1] = b2;
            byteArray[2] = b1;
            byteArray[3] = b0;

            // Get the correct integer value using the swapped bytes.  
            return BitConverter.ToInt32(byteArray, 0);
        }

        public static DateTime parseDateTime(long millis)
        {
            // Eingehendes Datum beginnt am 01.01.1970, ist in Millisekunden
            // DateTime zählt aber ab 0001
            DateTime date = DATE_TIME_OFFSET.AddMilliseconds(millis);
            date = date.ToLocalTime();

            return date;
        }

        public static long encodeDateTime(DateTime dt)
        {
            // DateTime zählt ab 0001
            // Android Datum beginnt aber am 01.01.1970, ist in Millisekunden
            return (dt.ToUniversalTime().Ticks - DATE_TIME_OFFSET.Ticks) / 10000L;
        }

    }
}
